import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class Client {

    public static void main(String[] args) throws Exception {

        //虚拟线程池
        var executor = Executors.newVirtualThreadPerTaskExecutor();

        // 从系统属性获取值，若未设置则使用默认值
        int appPort = Integer.parseInt(System.getProperty("appPort", "3389"));
        int remotePort = Integer.parseInt(System.getProperty("remotePort", "8888"));
        String remoteHost = System.getProperty("remoteHost", "192.168.1.195");


        var client = AsynchronousSocketChannel.open();
        Future<Void> connect = client.connect(new InetSocketAddress(remoteHost, remotePort));
        //等待连接
        connect.get();

        System.out.printf("客户端连接成功：appPort:%d,remotePort:%d,remoteHost:%s%n",appPort,remotePort,remoteHost);
        //写入100告诉服务端是用来交换数据的
        var buffer =  ByteBuffer.allocate(4).putInt(100).flip();
        var l = client.write(buffer).get();

        while (!Thread.interrupted()) {
            buffer = ByteBuffer.allocate(1);
            //读取服务端
            var len = client.read(buffer).get();
            if(len < 0){
                client.close();
            }else{
                //切换读
                buffer.flip();
                //服务端需要连接，提供连接
                if (buffer.get() == 66) {

                    executor.submit(() -> {
                        try (
                                //连接远程
                                var remote = AsynchronousSocketChannel.open();
                                //连接本地
                                var local = AsynchronousSocketChannel.open();
                        ) {

                            Future<Void> remoteConnect = remote.connect(new InetSocketAddress(remoteHost, remotePort));
                            Future<Void> localConnect = local.connect(new InetSocketAddress("localhost", appPort));

                            localConnect.get(3, TimeUnit.SECONDS);
                            remoteConnect.get(1, TimeUnit.SECONDS);
                            System.out.println(localConnect);

                            //告诉服务端是一个连接
                            var bf =  ByteBuffer.allocate(4).putInt(200).flip();
                            remote.write(bf).get(3, TimeUnit.SECONDS);

                            //开始交换数据
                            Future<?> taskFuture1 = executor.submit(() -> {
                                transferData(remote, local);
                            });

                            Future<?> taskFuture2 = executor.submit(() -> {
                                transferData(local, remote);
                            });

                            taskFuture1.get();
                            taskFuture2.get();

                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }

                    });

                } else {
                    client.close();
                    break;
                }
            }

        }

    }
    private static void transferData(AsynchronousSocketChannel srcChannel, AsynchronousSocketChannel dstChannel) {
        int readLen;
        do{
            try {
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                Future<Integer> read1 = srcChannel.read(buffer);
                readLen = read1.get();
                if(readLen>0){
                    buffer.flip();
                    while (buffer.remaining()>0){
                        Future<Integer> write1 = dstChannel.write(buffer);
                        write1.get();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                break;
            }
        }while (readLen>0);
    }
}
